package xorm

// Begin 开启一个事务
func (s *Session) Begin() error {
	if s.autoCommit {
		tx, err := s.DB().BeginTx(s.ctx, nil)
		if err != nil {
			return err
		}
		s.autoCommit = false
		s.commitOrRollback = false
		s.tx = tx

		s.saveLastSQL("BEGIN TRANSACTION")
	}
	return nil
}

// Rollback 使用事务时，如果有任何错误，您可以回滚。
func (s *Session) Rollback() error {
	if !s.autoCommit && !s.commitOrRollback {
		s.saveLastSQL("ROLL BACK")
		s.commitOrRollback = true
		s.autoCommit = true

		return s.tx.Rollback()
	}
	return nil
}

// Commit 使用事务时，提交所有操作。
func (s *Session) Commit() error {
	if !s.autoCommit && !s.commitOrRollback {
		s.saveLastSQL("COMMIT")
		s.commitOrRollback = true
		s.autoCommit = true

		if err := s.tx.Commit(); err != nil {
			return err
		}

		// handle processors after tx committed
		closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
			if closuresPtr != nil {
				for _, closure := range *closuresPtr {
					closure(bean)
				}
			}
		}

		for bean, closuresPtr := range s.afterInsertBeans {
			closureCallFunc(closuresPtr, bean)

			if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
				processor.AfterInsert()
			}
		}
		for bean, closuresPtr := range s.afterUpdateBeans {
			closureCallFunc(closuresPtr, bean)

			if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
				processor.AfterUpdate()
			}
		}
		for bean, closuresPtr := range s.afterDeleteBeans {
			closureCallFunc(closuresPtr, bean)

			if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
				processor.AfterDelete()
			}
		}
		cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
			if len(*slices) > 0 {
				*slices = make(map[interface{}]*[]func(interface{}), 0)
			}
		}
		cleanUpFunc(&s.afterInsertBeans)
		cleanUpFunc(&s.afterUpdateBeans)
		cleanUpFunc(&s.afterDeleteBeans)
	}
	return nil
}
